home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #2
/
Monster Media No. 2 (Monster Media)(1994).ISO
/
prog_pas
/
ddplus63.zip
/
DOORTUT2.DOC
< prev
next >
Wrap
Text File
|
1991-10-10
|
18KB
|
464 lines
------------------------------------------------------------------------------
Note: This article extracted from the September '91 issue of Carrier Detect
Journal. At this time, only part 1 of the series was available; Future
installments may be read in Carrier Detect Journal.
------------------------------------------------------------------------------
* Writing a BBS Door (Part 2)
Tutorial by Scott M. Baker
I am happy to say that response to the first door
tutorial has been very encouraging. We've received several
requests for further continuation of the series, so here
is the second installment. For those joining us for the
first time, this series is about how to write a "door"
program. We're programming in Turbo Pascal and using my
DoorDriver kit for support. I encourage any of you who
have not yet read part I to review as it contains some
important introductory material.
Last time, I said we'd dig deeper into some
interactive communication with the user. The best way to
do this is with a sample program. Our last sample, HLODOOR
was pretty plain, so let's write something that is a bit
more exciting.
The following is NUMDOOR.PAS: a simple little game
designed to demonstrate some interactive communication
with the user.
{ 1} program numdoor;
{ 2}
{ 3} uses doordriv;
{ 4}
{ 5} procedure DoTheTitle;
{ 6} begin;
{ 7} sclrscr;
{ 8} swriteln('Hello, '+user_first_name+
{ 9} ' '+user_last_name+
{10} '. Welcome to NumDoor!');
{11} swriteln('');
{12} end;
{13}
{14} procedure playgame;
{15} var
{16} thenum: word;
{17} playerguess: word;
{18} guessnum: byte;
{19} done: boolean;
{20} tempstr: string;
{21} begin;
{22} swriteln('I''m thinking of a number.'+
{23} ' Can you guess what it is?');
{24} swriteln('');
{25} guessnum:=0;
{26} randomize;
{27} thenum:=random(100)+1;
{28} done:=false;
{29} while not done do begin;
{30} inc(guessnum);
{31} swrite('Guess #');
{32} str(guessnum,tempstr);
{33} swrite(tempstr);
{34} swrite(': ');
{35} sread_num_word(playerguess);
{36} if playerguess>thenum then swriteln('Lower!') else
{37} if playerguess<thenum then swriteln('Higher!') else
{38} if playerguess=thenum then begin;
{39} swriteln('Correct!');
{40} done:=true;
{41} end;
{42} if guessnum=10 then done:=true;
{43} end; {while}
{44} if thenum<>playerguess then begin;
{45} swriteln('You Lost!');
{46} str(thenum,tempstr);
{47} swriteln('The number was '+tempstr+'.');
{48} end;
{49} end;
{50}
{51} procedure waitforkey;
{52} var
{53} ch: char;
{54} begin;
{55} swriteln('');
{56} swriteln('Press any key to continue.');
{57} sread_char(ch);
{58} end;
{59}
{60} begin;
{61} initdoordriver('DOORDRIV.CTL');
{62} dothetitle;
{63} playgame;
{64} waitforkey
{65} end.
Some of you were asking for a real door.. Well, there
it is. All 62 lines worth. Those of you using our new
LOCREAD program may wish to load up a second window on the
screen so you may view both the above source and the rest
of the article at the same time. On with the discussion...
First lets look at an overview of the structure of
NUMDOOR. We've got three main procedures: DoTheTitle,
PlayGame, and WaitForKey. These procedures are pretty self
explanatory. DoTheTitle displays a little title
information about NUMDOOR. PlayGame performs the actual
task of playing the game, and WaitForKey waits for the
user to press a key once the game is over.
Let's go through the program section by section. At
the very top, you'll notice lines one and three. Line 1
(Program NumDoor;) is simply us formally telling TP the
name of our program. Line 2 (Uses Doordriv;) is the
all-important "uses" statement which tells TP that we will
be using the DoorDriv TPU.
Procedure DoTheTitle
The first procedure, DoTheTitle displays a little
introduction to the user so he knows where he is. Let's
look inside this procedure and see how it works:
LINE 7: SCLRSCR;
This is a DoorDriver procedure which we have not
introduced before. Sclrscr is DoorDriver's compliment to
the Turbo Pascal clrscr procedure. The clrscr procedure is
provided by TP to allow us to clear the screen. If you're
familiar with basic, then this is equivalent to a CLS.
Obviously, we will need to clear both the remote and the
local screens, so that's why we have to use DoorDriver's
Sclrscr.
LINES 8-10: SWRITELN('Hello, '+user_first_name+ .....
These lines display the introduction. As we learned in
part one of this tutorial, SWRITELN is DoorDriver's
compliment to Turbo Pascal's writeln procedure. You may
notice that I have separated the parameters across three
lines. This is perfectly legal - as long as the individual
components include plus (+) signs in between them, we can
split it up that way.
Another important note about this line: We include the
variables USER_FIRST_NAME and USER_LAST_NAME. These were
discussed in part one. For those who may have missed it,
DoorDriver places the user's first and last names into
those two respective variables. Sticking them in the
SWRITELN allows us to be a bit more personal to the user.
LINE 11: SWRITELN('');
You may be wondering, what is the point of writing
_nothing_ to the screen? The point is, like TP's writeln,
swriteln will output a CR/LF sequence. So even if we do
not write any data, the Carriage Return still goes out.
The effect is a blank line.
Procedure PlayGame
PlayGame is where all of the real work takes place.
Let's take a minute to talk about what exactly the "game"
is that we are playing.
The game is a very common number guessing game. The
computer generates a random number and the user gets ten
shots to guess what it is. If the user guesses
incorrectly, the computer will tell whether he needs to go
"higher" or "lower". Now that we know what we want to do,
lets see how we would go about doing it. In pseudocode,
here's what we need to do:
1) Generate a random number
2) Ask the user for a guess
3) Compare the user's guess to our random number.
4) Say "lower", "higher", or "correct" based on the
outcome of #3's comparison.
5) Loop back to 2 until either the user guesses the
number correctly or uses up all ten tries.
6) If the user used up all ten tries, tell him he
lost.
That's our strategy. Now, let's go thought the actual
code.
LINES 16-20: Variable Declarations
We need a multitude of variables to store some of our
information in. THENUM is a word variable which will hold
the random number which we generate. PLAYERGUESS is
another word to hold the player's current guess. GUESSNUM
is a counter to hold how many times the user has guessed.
DONE is a boolean to tell us when we are done. And
finally, TEMPSTR is a temporary string which we will
discuss when we come to it.
LINES 22-24: SWRITELN('I''m thinking of .....
These lines comprise a little instruction that we give
the user. They're just simple swriteln statements, similar
to the ones we encountered in DoTheTitle.
LINE 25: GUESSNUM:=0;
Since Turbo Pascal does not initialize our variables,
we will have to do it ourselves. Guessnum is our counter
of how many guesses the user has made. Since he hasn't
made any yet, we've got to set it to zero.
LINE 26: RANDOMIZE;
The Randomize procedure is provided by Turbo Pascal to
randomize TP's random number generator. Without it, the
game would pick the same random number each time it runs.
LINE 27: THENUM:=RANDOM(100)+1
Here is where we get our random number. The random
function returns a number between zero and it's parameter
minus one. (i.e. Random(100) will include 0..99, not 100)
So we add 1 to it to get numbers between 1 and 100.
LINE 28: DONE:=FALSE;
Right now, we aren't done yet, (we haven't even hardly
started!) so we'd better set our variable accordingly.
LINE 29: WHILE NOT DONE DO BEGIN;
Line 29 sets up our "loop" which will ask the user for
up to ten guesses. We want to keep going as long as DONE
is not true. The loop consists of lines 29-43 which ask
the user for his guess and check it's validity.
LINE 30: INC(GUESSNUM);
We're on the first guess, so set guessnum accordingly.
LINES 31-34: SWRITE('Guess #' .....
These lines prompt the user for his guess. Although
they may seem complicated, they are really nothing more
than the simple SWRITE statements that we have seen
before. We just need to do some "magic" to manipulate our
data.
Let me explain our problem: SWRITE/SWRITELN only
accept string data. But, our variable GUESSNUM is a byte
variable which holds numeric information. So how do we get
this data into something we can use? The answer is that we
use Turbo Pascal's STR procedure. STR is a very handy
procedure which converts a numeric format variable to a
string format variable. So, when we say
STR(GUESSNUM,TEMPSTR), we are telling pascal to "take the
number in guessnum, convert it to a string, and place it
in tempstr".
Once this has been done, TEMPSTR now contains our
number which we can send out to swrite with no problem.
LINE 35: SREAD_NUM_WORD(PLAYERGUESS);
This line the major new concept that we are trying to
introduce. SREAD_NUM_WORD is a DoorDriver procedure which
will read a word variable from the user. It handles all
the details of waiting for the user to press keys,
converting the data to a word, etc and just gives us a
nice word variable.
This is where the "interaction" takes place. Until
now, we have just been displaying information to the user.
Now, we ask the user for some information back.
Specifically, we ask him for his guess. The guess is
stored in the variable PLAYERGUESS.
LINES 36-41: If playerguess>thenum then ....
This block comprises the code to test the player's
guess and act upon the results. We display "higher" or
"lower" if the number is higher or lower and if the user's
guess is correct, we display "correct" and set DONE to
true to end our loop.
This code is all standard pascal stuff (with some
swrites thrown) in so I won't go into too much detail
here. We've got to try to stick to the doordriver-related
things or our little tutorial could get very big very
quickly.
LINE 42: IF GUESSNUM=10 THEN DONE:=TRUE;
If we're at the tenth guess, then it's time to end our
loop.
LINES 44-48: IF PLAYERGUSS<>THENUM THEN BEGIN; ....
We could have exited the loop for one of two reasons:
1) The user guessed correctly and DONE was set to true or
2) The user ran out of turns. These lines will check and
see if the user's guess was correct. If it was not, then
we got to break the bad news to him - he lost.
This code also includes our little trick of using STR
to convert the data. In this case, we have THENUM and we
need to convert it to a string so we can tell the user
what the number was. It works identically to the situation
we had in lines 31-34.
Procedure WaitForKey
After we have finished PlayGame, we need to have a
little pause so the user gets to absorb the full impact of
his game playing. We could use a simple DELAY(2000) for a
20 second delay, but we are out to demonstrate interactive
communication, so let's wait for a keypress.
I'm not going into this line-by-line as it is such a
simple procedure. Rather, I'll describe what it does.
First, we tell the user we want him to hit a key with a
SWRITELN statement.
Then, we use DoorDriver's SREAD_CHAR procedure to read
a single character. SREAD_CHAR will wait for a key and
then return it to us. We used the variable CH to hold this
character.
The Main Procedure
The main procedure, comprising lines 60-65 executes
all of our other procedure. Please note that similar to
HLODOOR, we had to call INITDOORDRIVER() to get DoorDriver
setup and ready for use.
After that, we just called DoTheTitle, PlayGame, and
WaitForKey in order. Then, we exit.
Interactive Routines
We have introduced two new very important routines:
SREAD_NUM_WORD and SREAD_CHAR. DoorDriver includes a whole
set of similar routines for doing similar things. Here's a
listing of them:
SREAD(s: string); Reads in a string
SREAD_NUM(i: integer); Reads in an integer
SREAD_NUM_WORD(w: word); Reads in a word
SREAD_NUM_LONGINT(l: longint); Reads in a longint
SREAD_CHAR(CH: CHAR); Reads in a char
The first four of these routines will read in data
until the user presses the return key. For example
"1234"<return>. They allow the user to backspace back and
forth to correct his mistakes. These are very similar to
Turbo Pascal's READLN and Basic's INPUT statements.
The fifth procedure (SREAD_CHAR) will wait for a
character and return that character. It's simply for when
you want one character and only one character. The user
can't correct his mistakes with backspace or anything.
This routine also does not echo to the screen.
SREAD_CHAR performs almost identically to Turbo
Pascal's READKEY function. In Turbo Pascal you would use
ch:=READKEY; With DoorDriver, use SREAD_CHAR(CH).
Conclusion
This installment has turned out a lot longer than I
had anticipated. However, we have gained some very
important knowledge. We now know how to ask the user for
data.
If you like, play with DD's other input routines
(SREAD,SREAD_NUM, etc) and see what you can do with them.
They are very important to the operation of a door.
You might also want to try altering the look and feel
of NUMDOOR. You can expand the SWRITELN statements to
provide a more impressive instruction and title section.
Or if you are feeling really adventurous, you may want to
look in the DoorDriver manual and peek into the
SET_FOREGROUND procedure which will let you set the color
of the text. That is one of the key things we will
introduce next time.
Please, if you have any questions or suggestions, you
can either send them directly or to Michael Crosson,
editor and published of Carrier Detect. I am right now
still deciding in which direction to take this series -
should we work on creating one large program? Or introduce
features with a lot more small programs such as NUMDOOR
and HLODOOR. You tell me!